#include "ESP8266.h"
#include <cstring>
#include <cstdio>
using namespace std;
const char* ESP8266::NET_Status_String[] =
{
	"Error",
	"Error",
	"GetIP",
	"Connection",
	"LostConnect",
	"NoWIFI",
};


bool ESP8266::CheckReturn(const char* Res, uint16_t Timeout)
{
	Timeout/=50;
	while(Timeout-- and not ReciveFlag)//等待接收完成
		Delay.ms(50);

	if(Timeout==0)//超时
		return false;

	return (bool)strstr((char*)this->Buffer,Res);//查找返回值并返回结果
}

void ESP8266::ClearBuffer(void)
{
	this->ReciveFlag = false;
	this->ReciveLength = 0;
	this->Buffer[0] = '\0';
#if USE_DMA
	RxChannel.Off();
	RxChannel.SetCurrDataCounter(sizeof(this->Buffer));
	RxChannel.On();
#endif
}

bool ESP8266::SendCmd(const char* CMD, const char* Res, uint16_t Timeout, uint16_t Retry)
{
	while(Retry--)//循环尝试
	{
		this->ClearBuffer();//清空缓冲区
		Port<<CMD<<endl;//发送命令
		if(this->CheckReturn(Res,Timeout))//如果有正确的回复
			return true;//返回真
		Delay.ms(Timeout);//否则延迟再次发送
	}
	return false;//重发多次均失败
}

void ESP8266::Init(void)
{
	Delay.ms(3000);
	if(not this->CheckModel())
		throw "Model Error";

	if(not this->SetFeedBack(false))//关闭命令回显，模组仅返回命令结果
		throw "ATE Error";

	bool ifDelay = false;
	for(int i=0; i<3; i++)
	{
		auto Sta = this->GetNetworkStatus();//获取网络状态
		switch(Sta)
		{
			case Error:
				ifDelay = true;//需要延时再试
				continue;
//				break;

			case Connection:
				break;

			case GetIP:
			case LostConnect:
				ifDelay = not this->BuildConnection("TCP","183.230.40.39",876);//和EDP服务器建立TCP连接
				break;

			case NoWIFI:
				throw NoWIFI;

		}
		if(ifDelay)
			Delay.ms(5000);
		else
			break;//结束循环
	}//for循环结束
	if(ifDelay)//超出循环次数
		throw "Network Status Error";//说明三次均为异常情况或无法建立TCP连接

	//运行到此处，说明模组本身正常，网络状态正常且已经建立TCP连接
}

bool ESP8266::Reboot(void)
{
	if(not this->SendCmd("AT+RST","OK",1000,3))
		return false;
#if USE_DMA
	RxChannel.Off();//拒绝接收重启后模块的杂乱数据
	Delay.ms(3000);
	RxChannel.On();
#else
	Delay.ms(3000);
#endif
	if(not this->CheckModel())//重启后检查模组存在性
		return false;//不存在即为重启失败

	return true;
}

bool ESP8266::CheckModel(void)
{
	return this->SendCmd("AT","OK",1000,5);
}

bool ESP8266::SendDataPrepare(uint32_t DataLen)
{
	char buf[64];
	snprintf(buf,sizeof(buf),"AT+CIPSEND=%d",DataLen);
	return this->SendCmd(buf,"OK",1000,5);
}

ESP8266::NET_Status_t ESP8266::GetNetworkStatus(void)
{
	volatile NET_Status_t Sta = Error;
	if(this->SendCmd("AT+CIPSTATUS","OK",1000,3))
	{
		auto dp = strstr((char*)this->Buffer,"STATUS");
		if(dp!=nullptr)
			sscanf(dp,"STATUS:%d",(int*)&Sta);//扫描读入参数
	}
	return Sta;
}

bool ESP8266::SetFeedBack(bool OF)
{
	char buf[5];
	snprintf(buf,sizeof(buf),"ATE%d",OF);
	return this->SendCmd(buf,"OK",1000,3);
}

bool ESP8266::ConnectWIFI(const char* SSID, const char* Password)
{
	char buf[64];
	snprintf(buf,sizeof(buf),"AT+CWJAP=\"%s\",\"%s\"",SSID,Password);
	return this->SendCmd(buf,"OK",5000,3);
}

bool ESP8266::DisConnectWIFI(void)
{
	const char* CMD = "AT+CWQAP";
	return this->SendCmd(CMD,"OK",1000,3);
}

bool ESP8266::SetMode(Mode_t Mode)
{
	char buf[16];
	snprintf(buf,sizeof(buf),"AT+CWMODE=%d",(int)Mode);
	return this->SendCmd(buf,"OK",3000,3);
}

bool ESP8266::SetWIFIAutoConnect(bool OF)
{
	char buf[24];
	snprintf(buf,sizeof(buf),"AT+CWAUTOCONN=%d",OF);
	return this->SendCmd(buf,"OK",3000,3);
}

bool ESP8266::SetSmartConfig(ConfigMethod_t Method)
{
	char buf[24];
	snprintf(buf,sizeof(buf),"AT+CWSMARTSTART=%d",(int)Method);
	return this->SendCmd(buf,"OK",1000,3);
}

bool ESP8266::StopSmartConfig(void)
{
	return this->SendCmd("AT+CWSMARTSTOP","OK",1000,3);
}

bool ESP8266::SetDirectTransmit(bool OF)
{
	char buf[16];
	snprintf(buf,sizeof(buf),"AT+CIPMODE=%d",OF);
	return this->SendCmd(buf,"OK",1000,5);
}

bool ESP8266::BuildConnection(const char* Type, const char* Address, uint32_t _Port)
{
	char buf[64];
	snprintf(buf,sizeof(buf),"AT+CIPSTART=\"%s\",\"%s\",%d",Type,Address,_Port);
	return this->SendCmd(buf,"OK",5000,5);
}

bool ESP8266::GetReciveData(uint8_t** dp)
{
	auto pRes = strstr((char*)Buffer,"+IPD");
	if(pRes!=nullptr)
	{
		*dp = (uint8_t*)strchr(pRes,':')+1;
		return true;
	}
	return false;
}
